﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;
using Moq;

namespace MvcWiki.Test.Repository.UnitOfWork
{
    public class SavedFacts
    {
        [Fact]
        public void Can_Call()
        {
            var unitOfWorkPersistence = new Mock<MvcWiki.Repository.IUnitOfWorkPersistence>();

            var unitOfWork = new MvcWiki.Repository.UnitOfWork();

            var entity = new MvcWiki.Model.WikiPage();

            unitOfWork.Saved(entity, unitOfWorkPersistence.Object);
        }

        [Fact]
        public void Calls_IUnitOfWorkPersistence_InsertEntity_On_Commit()
        {
            var entity = new MvcWiki.Model.WikiPage();

            var unitOfWorkPersistence = new Mock<MvcWiki.Repository.IUnitOfWorkPersistence>();
            unitOfWorkPersistence.Setup(x => x.InsertEntity(entity));

            var unitOfWork = new MvcWiki.Repository.UnitOfWork();

            unitOfWork.Saved(entity, unitOfWorkPersistence.Object);

            unitOfWork.Commit();

            unitOfWorkPersistence.VerifyAll();
        }

        [Fact]
        public void Calls_IUnitOfWorkPersistence_Insert_For_WikiNamespaces_Then_For_WikiPages()
        {
            var wikiPage = new MvcWiki.Model.WikiPage();
            var wikiNamespace = new MvcWiki.Model.WikiNamespace();

            bool wikiNamespaceInsertedLast = false;
            bool wikiPageInsertedLast = false;

            var unitOfWorkPersistenceForWikiPage = new Mock<MvcWiki.Repository.IUnitOfWorkPersistence>();
            unitOfWorkPersistenceForWikiPage.Setup(x => x.InsertEntity(wikiPage))
                .Callback(() => { wikiNamespaceInsertedLast = false; wikiPageInsertedLast = true; });

            var unitOfWorkPersistenceForWikiNamespace = new Mock<MvcWiki.Repository.IUnitOfWorkPersistence>();
            unitOfWorkPersistenceForWikiNamespace.Setup(x => x.InsertEntity(wikiNamespace))
                .Callback(() => { wikiNamespaceInsertedLast = true; wikiPageInsertedLast = false; });

            var unitOfWork = new MvcWiki.Repository.UnitOfWork();

            unitOfWork.Saved(wikiPage, unitOfWorkPersistenceForWikiPage.Object);
            unitOfWork.Saved(wikiNamespace, unitOfWorkPersistenceForWikiNamespace.Object);

            unitOfWork.Commit();

            Assert.False(wikiNamespaceInsertedLast);
            Assert.True(wikiPageInsertedLast);
        }

        [Fact]
        public void Does_Not_Call_IUnitOfWorkPersistence_InsertEntity_On_Second_Commit()
        {
            var entity = new MvcWiki.Model.WikiPage();

            var insertEntityCalls = 0;

            var unitOfWorkPersistence = new Mock<MvcWiki.Repository.IUnitOfWorkPersistence>();
            unitOfWorkPersistence.Setup(x => x.InsertEntity(entity)).Callback(() => insertEntityCalls++);

            var unitOfWork = new MvcWiki.Repository.UnitOfWork();

            unitOfWork.Saved(entity, unitOfWorkPersistence.Object);

            unitOfWork.Commit();
            unitOfWork.Commit();

            Assert.Equal<int>(1, insertEntityCalls);
        }

        [Fact]
        public void Calls_IUnitOfWorkPersistence_UpdateEntity_On_Commit_If_Entity_Was_Selected()
        {
            var entity = new MvcWiki.Model.WikiPage();

            var unitOfWorkPersistence = new Mock<MvcWiki.Repository.IUnitOfWorkPersistence>();
            unitOfWorkPersistence.Setup(x => x.UpdateEntity(entity));

            var unitOfWork = new MvcWiki.Repository.UnitOfWork();

            unitOfWork.Selected(entity, unitOfWorkPersistence.Object);
            unitOfWork.Saved(entity, unitOfWorkPersistence.Object);

            unitOfWork.Commit();

            unitOfWorkPersistence.VerifyAll();
        }
    }
}
